package com.atguigu.daijia.driver.service.impl;

import com.atguigu.daijia.common.constant.SystemConstant;
import com.atguigu.daijia.common.execption.GuiguException;
import com.atguigu.daijia.common.result.ResultCodeEnum;
import com.atguigu.daijia.common.util.LocationUtil;
import com.atguigu.daijia.dispatch.client.NewOrderFeignClient;
import com.atguigu.daijia.driver.service.OrderService;
import com.atguigu.daijia.map.client.LocationFeignClient;
import com.atguigu.daijia.map.client.MapFeignClient;
import com.atguigu.daijia.model.entity.order.OrderInfo;
import com.atguigu.daijia.model.entity.order.OrderProfitsharing;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.map.CalculateDrivingLineForm;
import com.atguigu.daijia.model.form.order.OrderFeeForm;
import com.atguigu.daijia.model.form.order.StartDriveForm;
import com.atguigu.daijia.model.form.order.UpdateOrderBillForm;
import com.atguigu.daijia.model.form.order.UpdateOrderCartForm;
import com.atguigu.daijia.model.form.rules.FeeRuleRequestForm;
import com.atguigu.daijia.model.form.rules.ProfitsharingRuleRequestForm;
import com.atguigu.daijia.model.form.rules.RewardRuleRequest;
import com.atguigu.daijia.model.form.rules.RewardRuleRequestForm;
import com.atguigu.daijia.model.vo.base.PageVo;
import com.atguigu.daijia.model.vo.map.DrivingLineVo;
import com.atguigu.daijia.model.vo.map.OrderLocationVo;
import com.atguigu.daijia.model.vo.map.OrderServiceLastLocationVo;
import com.atguigu.daijia.model.vo.order.*;
import com.atguigu.daijia.model.vo.rules.FeeRuleResponseVo;
import com.atguigu.daijia.model.vo.rules.ProfitsharingRuleResponseVo;
import com.atguigu.daijia.model.vo.rules.RewardRuleResponseVo;
import com.atguigu.daijia.order.client.OrderInfoFeignClient;
import com.atguigu.daijia.rules.client.FeeRuleFeignClient;
import com.atguigu.daijia.rules.client.ProfitsharingRuleFeignClient;
import com.atguigu.daijia.rules.client.RewardRuleFeignClient;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderInfoFeignClient orderInfoFeignClient;
    @Resource
    private NewOrderFeignClient newOrderFeignClient;
    @Resource
    private MapFeignClient mapFeignClient;
    @Resource
    private LocationFeignClient locationFeignClient;

    @Resource
    private FeeRuleFeignClient feeRuleFeignClient;

    @Resource
    private RewardRuleFeignClient rewardRuleFeignClient;

    @Resource
    private ProfitsharingRuleFeignClient profitsharingRuleFeignClient;
    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

    @Override
    public Integer getOrderStatus(Long orderId) {
        return orderInfoFeignClient.getOrderStatus(orderId).getData();
    }

    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        return newOrderFeignClient.findNewOrderQueueData(driverId).getData();
    }

    @Override
    public Boolean robNewOrder(Long driverId, Long orderId) {
        return orderInfoFeignClient.robNewOrder(driverId, orderId).getData();
    }

    @Override
    public CurrentOrderInfoVo searchDriverCurrentOrder(Long driverId) {
        return orderInfoFeignClient.searchDriverCurrentOrder(driverId).getData();
    }

    @Override
    public OrderInfoVo getOrderInfo(Long orderId, Long driverId) {
        OrderInfo orderInfo = orderInfoFeignClient.getOrderInfo(orderId).getData();
        if(orderInfo.getDriverId().longValue() != driverId.longValue()) {
            throw new GuiguException(ResultCodeEnum.ILLEGAL_REQUEST);
        }
        OrderBillVo orderBillVo = null;
        OrderProfitsharingVo orderProfitsharingVo = null;

        //获取账单信息和分账信息
        if(orderInfo.getStatus().intValue() > OrderStatus.END_SERVICE.getStatus().intValue()){
            orderBillVo = orderInfoFeignClient.getOrderBillInfo(orderId).getData();
            orderProfitsharingVo = orderInfoFeignClient.getOrderProfitsharing(orderId).getData();
        }

        OrderInfoVo orderInfoVo = new OrderInfoVo();
        orderInfoVo.setOrderId(orderId);
        BeanUtils.copyProperties(orderInfo, orderInfoVo);
        orderInfoVo.setOrderBillVo(orderBillVo);
        orderInfoVo.setOrderProfitsharingVo(orderProfitsharingVo);
        return orderInfoVo;
    }

    @Override
    public DrivingLineVo calculateDrivingLine(CalculateDrivingLineForm calculateDrivingLineForm) {
        return mapFeignClient.calculateDrivingLine(calculateDrivingLineForm).getData();
    }

    @Override
    public Boolean driverArriveStartLocation(Long orderId, Long driverId) {
        //防止刷单，计算司机的经纬度与代驾的起始经纬度是否在1公里范围内
        OrderInfo orderInfo = orderInfoFeignClient.getOrderInfo(orderId).getData();
        OrderLocationVo orderLocationVo = locationFeignClient.getCacheOrderLocation(orderId).getData();
        //司机的位置与代驾起始点位置的距离
        double distance = LocationUtil.getDistance(orderInfo.getStartPointLatitude().doubleValue(), orderInfo.getStartPointLongitude().doubleValue(), orderLocationVo.getLatitude().doubleValue(), orderLocationVo.getLongitude().doubleValue());
        if(distance > SystemConstant.DRIVER_START_LOCATION_DISTION) {
            throw new GuiguException(ResultCodeEnum.DRIVER_START_LOCATION_DISTION_ERROR);
        }
        return orderInfoFeignClient.driverArriveStartLocation(orderId, driverId).getData();
    }

    @Override
    public Boolean updateOrderCart(UpdateOrderCartForm updateOrderCartForm) {
        return orderInfoFeignClient.updateOrderCart(updateOrderCartForm).getData();
    }

    @Override
    public Boolean startDrive(StartDriveForm startDriveForm) {
        return orderInfoFeignClient.startDrive(startDriveForm).getData();
    }

    @Override
    public Boolean endDrive(OrderFeeForm orderFeeForm) {
        try {
            //获取订单信息
            CompletableFuture<OrderInfo> orderInfoCompletableFuture = CompletableFuture.supplyAsync(() -> {
                return orderInfoFeignClient.getOrderInfo(orderFeeForm.getOrderId()).getData();
            }, threadPoolExecutor);

            //2.防止刷单，计算司机的经纬度与代驾的终点经纬度是否在2公里范围内
            CompletableFuture<OrderServiceLastLocationVo> orderServiceLastLocationCompletableFuture = CompletableFuture.supplyAsync(() -> {
                return locationFeignClient.getOrderServiceLastLocation(orderFeeForm.getOrderId()).getData();
            }, threadPoolExecutor);

            CompletableFuture.allOf(orderInfoCompletableFuture,
                    orderServiceLastLocationCompletableFuture).join();
            //司机的位置与代驾终点位置的距离
            OrderInfo orderInfo = orderInfoCompletableFuture.get();
            OrderServiceLastLocationVo orderServiceLastLocationVo = orderServiceLastLocationCompletableFuture.get();
            double distance = LocationUtil.getDistance(orderInfo.getEndPointLatitude().doubleValue(), orderInfo.getEndPointLongitude().doubleValue(), orderServiceLastLocationVo.getLatitude().doubleValue(), orderServiceLastLocationVo.getLongitude().doubleValue());
            if (distance > SystemConstant.DRIVER_START_LOCATION_DISTION) {
                throw new GuiguException(ResultCodeEnum.DRIVER_END_LOCATION_DISTION_ERROR);
            }

            //计算订单实际里程
            CompletableFuture<BigDecimal> realDistanceCompletableFuture = CompletableFuture.supplyAsync(() -> {
                return locationFeignClient.calculateOrderRealDistance(orderFeeForm.getOrderId()).getData();
            }, threadPoolExecutor);
            //计算代价实际费用
            CompletableFuture<FeeRuleResponseVo> feeRuleResponseVoCompletableFuture = realDistanceCompletableFuture.
                    thenApplyAsync((realDistance) -> {
                        FeeRuleRequestForm feeRuleRequestForm = new FeeRuleRequestForm();
                        feeRuleRequestForm.setDistance(realDistance);
                        feeRuleRequestForm.setStartTime(orderInfo.getStartServiceTime());
                        Integer waitMinute = Math.abs((int)
                                (orderInfo.getArriveTime().getTime() - orderInfo.getAcceptTime().getTime() / (1000 * 60)));
                        feeRuleRequestForm.setWaitMinute(waitMinute);
                        FeeRuleResponseVo feeRuleResponseVo = feeRuleFeignClient.calculateOrderFee(feeRuleRequestForm).getData();
                        BigDecimal totalAmount = feeRuleResponseVo.getTotalAmount().add(orderFeeForm.getTollFee()).
                                add(orderFeeForm.getOtherFee()).add(orderFeeForm.getParkingFee()).add(orderInfo.getFavourFee());
                        feeRuleResponseVo.setTotalAmount(totalAmount);
                        return feeRuleResponseVo;
                    }, threadPoolExecutor);

            //计算系统奖励
            CompletableFuture<Long> orderNumCompletableFuture = CompletableFuture.supplyAsync(() -> {
                String startTime = new DateTime(orderInfo.getStartServiceTime()).toString("yyyy-MM-dd") + "00:00:00";
                String endTime = new DateTime(orderInfo.getEndServiceTime()).toString("yyyy-MM-dd") + "23:59:59";
                return orderInfoFeignClient.getOrderNumByTime(startTime, endTime).getData();
            }, threadPoolExecutor);

            CompletableFuture<RewardRuleResponseVo> rewardRuleResponseVoCompletableFuture = orderNumCompletableFuture.
                    thenApplyAsync((orderNum) -> {
                        RewardRuleRequestForm rewardRuleRequestForm = new RewardRuleRequestForm();
                        rewardRuleRequestForm.setOrderNum(orderNum);
                        rewardRuleRequestForm.setStartTime(orderInfo.getStartServiceTime());
                        return rewardRuleFeignClient.calculateOrderRewardFee(rewardRuleRequestForm).getData();
                    }, threadPoolExecutor);


            //计算分账信息
            CompletableFuture<ProfitsharingRuleResponseVo> profitsharingRuleResponseVoCompletableFuture =
                    feeRuleResponseVoCompletableFuture.thenCombineAsync(orderNumCompletableFuture, (feeRuleResponseVo, orderNum) -> {
                        ProfitsharingRuleRequestForm profitsharingRuleRequestForm = new ProfitsharingRuleRequestForm();
                        profitsharingRuleRequestForm.setOrderAmount(feeRuleResponseVo.getTotalAmount());
                        profitsharingRuleRequestForm.setOrderNum(orderNum);
                        return profitsharingRuleFeignClient.calculateOrderProfitsharingFee(profitsharingRuleRequestForm).getData();
                    }, threadPoolExecutor);

            CompletableFuture.allOf(orderInfoCompletableFuture,
                    realDistanceCompletableFuture,
                    feeRuleResponseVoCompletableFuture,
                    orderNumCompletableFuture,
                    rewardRuleResponseVoCompletableFuture,
                    profitsharingRuleResponseVoCompletableFuture).join();
            //获取执行结果
            BigDecimal realDistance = realDistanceCompletableFuture.get();
            FeeRuleResponseVo feeRuleResponseVo = feeRuleResponseVoCompletableFuture.get();
            RewardRuleResponseVo rewardRuleResponseVo = rewardRuleResponseVoCompletableFuture.get();
            ProfitsharingRuleResponseVo profitsharingRuleResponseVo = profitsharingRuleResponseVoCompletableFuture.get();

            //封装更新订单账单相关实体对象
            UpdateOrderBillForm updateOrderBillForm = new UpdateOrderBillForm();
            updateOrderBillForm.setOrderId(orderFeeForm.getOrderId());
            updateOrderBillForm.setDriverId(orderFeeForm.getDriverId());
            //额外费用
            updateOrderBillForm.setOtherFee(orderFeeForm.getOtherFee());
            updateOrderBillForm.setTollFee(orderFeeForm.getTollFee());
            updateOrderBillForm.setParkingFee(orderFeeForm.getParkingFee());
            //乘客好处费
            updateOrderBillForm.setFavourFee(orderInfo.getFavourFee());
            //实际距离
            updateOrderBillForm.setRealDistance(realDistance);

            //代价费用信息
            BeanUtils.copyProperties(feeRuleResponseVo, updateOrderBillForm);
            //分账信息
            BeanUtils.copyProperties(profitsharingRuleResponseVo, updateOrderBillForm);
            //系统奖励信息
            BeanUtils.copyProperties(rewardRuleResponseVo, updateOrderBillForm);

            //结束代价更新账单
            orderInfoFeignClient.endDrive(updateOrderBillForm);

            return true;
        }catch (Exception e){
            throw new RuntimeException("订单结束失败");
        }
    }

    @Override
    public PageVo findDriverOrderPage(Long driverId, Long page, Long limit) {
        return orderInfoFeignClient.findDriverOrderPage(driverId, page, limit).getData();
    }

    @Override
    public Boolean sendOrderBillInfo(Long orderId, Long driverId) {
        return orderInfoFeignClient.sendOrderBillInfo(orderId, driverId).getData();
    }
}
